package com.nightpiter.view.drawer.dynamic;

import static com.nightpiter.view.drawer.dynamic.Config.hubRadius;

import java.util.ArrayList;

import com.nightpiter.model.objects.Station;
import com.nightpiter.view.Calculator;
import com.nightpiter.view.graphics.Canvas;
import com.nightpiter.view.graphics.Color;
import com.nightpiter.view.graphics.PointF;
import com.nightpiter.view.graphics.RadialGradient;
import com.nightpiter.view.graphics.RectF;

/**
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 * 
 */
class IntermediateAmoeba extends Amoeba implements
		Comparable<IntermediateAmoeba> {

	/** child amoebas */
	private Amoeba leftAmoeba, rightAmoeba;

	private PointF distantCoordF;

	private float distance;

	private int order;

	/**
	 * @param leftAmoeba
	 * @param rightAmoeba
	 */
	public IntermediateAmoeba(Amoeba leftAmoeba, Amoeba rightAmoeba) {
		this.leftAmoeba = leftAmoeba;
		this.rightAmoeba = rightAmoeba;
		// TODO
		assert (leftAmoeba.amoebaUltimate == rightAmoeba.amoebaUltimate);
		this.amoebaUltimate = leftAmoeba.amoebaUltimate;
		order = amoebaUltimate.getNextOrder();
		assert (leftAmoeba.intermediateAmoeba == null && rightAmoeba.intermediateAmoeba == null);
		leftAmoeba.intermediateAmoeba = this;
		rightAmoeba.intermediateAmoeba = this;
		leftAmoeba.brotherAmoeba = rightAmoeba;
		rightAmoeba.brotherAmoeba = leftAmoeba;

		this.size = leftAmoeba.size + rightAmoeba.size;

		this.stations = new Station[size];
		this.colors = new int[size];
		this.coords = new PointF[size];
		int k = 0;
		for (int i = 0; i < leftAmoeba.size; i++, k++) {
			stations[k] = leftAmoeba.stations[i];
			colors[k] = leftAmoeba.colors[i];
			coords[k] = leftAmoeba.coords[i];
		}
		for (int i = 0; i < rightAmoeba.size; i++, k++) {
			stations[k] = rightAmoeba.stations[i];
			colors[k] = rightAmoeba.colors[i];
			coords[k] = rightAmoeba.coords[i];
		}

		PointF coordF = PointF.averaged(leftAmoeba.coordF, rightAmoeba.coordF,
				leftAmoeba.size, rightAmoeba.size);

		float maxDistance = Float.NEGATIVE_INFINITY;
		float distance;
		for (PointF eachCoordF : this.coords) {
			distance = coordF.distanceTo(eachCoordF);
			if (distance > maxDistance) {
				maxDistance = distance;
				distantCoordF = eachCoordF;
			}
		}
		this.distance = maxDistance;

		this.coordF = coordF;
	}

	private PointF distantPointF = new PointF();

	private RectF arcRectF = new RectF();

	private float currentDistance;

	@Override
	protected void applyCalculator(Calculator calculator) {
		calculator.convert(distantCoordF, distantPointF);
		calculator.convert(coordF, pointF);
		currentDistance = pointF.distanceTo(distantPointF);
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.applyCalculator(calculator);
			rightAmoeba.applyCalculator(calculator);
		}
	}

	@Override
	protected void addDrawnAmoebas(ArrayList<Amoeba> drawnAmoebas) {
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.addDrawnAmoebas(drawnAmoebas);
			rightAmoeba.addDrawnAmoebas(drawnAmoebas);
		} else {
			drawnAmoebas.add(this);
		}
	}

	@Override
	protected void draw(Canvas canvas) {
		if (currentDistance > Config.mergeDistance) {
			leftAmoeba.draw(canvas);
			rightAmoeba.draw(canvas);

		} else {
			canvas.drawPoint(pointF, backComplexPaint);
			arcRectF.set(pointF.x - hubRadius / 2, pointF.y - hubRadius / 2,
					pointF.x + hubRadius / 2, pointF.y + hubRadius / 2);
			float sector = 360 / size;
			float angle = 90;
			for (int color : colors) {
				complexPaint.setShader(new RadialGradient(pointF.x + 1,
						pointF.y + 1, (float) (hubRadius * 1.3), Color.WHITE,
						color));
				canvas.drawArc(arcRectF, angle, sector, complexPaint);
				angle += sector;
			}

			this.drawLabels(canvas);
		}
	}

	@Override
	protected void highlight(Canvas canvas, int highlightColor) {
		if (currentDistance <= Config.mergeDistance) {
			lightComplexPaint.setColor(highlightColor);
			canvas.drawPoint(pointF, lightComplexPaint);
			draw(canvas);
		}
	}

	public float getCurrentDistance() {
		return currentDistance;
	}

	public int compareTo(IntermediateAmoeba another) {
		if (this.distance < another.distance) {
			return -1;
		}
		if (this.distance > another.distance) {
			return 1;
		}
		return (int) Math.signum(this.order - another.order);
	}

}
